<template>
  <div>
    <el-card>
    <category-selector :disabled="!isShowList"></category-selector>
  </el-card>
  <el-card style="margin-top:20px">
    <div v-show="isShowList">
      <el-button  type:="primary" :icon="Plus" @click="showAdd" :disabled="!category3Id" v-has="'btn.Attr.add'">
        添加属性
      </el-button>
      <el-table border :data="attrList">
        <el-table-column label="序号" type="index" align="center" width="80"></el-table-column>
        <el-table-column label="属性名称" width="150" prop="attrName"></el-table-column>
        <el-table-column label="属性值列表">
          <template v-slot="{row}">
            <el-tag  v-for=" value in row.attrValueList" :key="value.id" style="margin-right: 5px;">
              {{ value.valueName }}
            </el-tag>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="150">
          <template v-slot="{row}">
            <el-button type="primary" :icon="Edit" size="small" @click="showUpdate(row)" v-has="'btn.Attr.update'"></el-button>
            <el-popconfirm :title="`确定删除${row.attrName}吗?`" @confirm="remove(row.id)" >
            <template #reference>
              <el-button type="danger" :icon="Delete" size="small" v-has="'btn.Attr.remove'"></el-button>
            </template>
          </el-popconfirm>
          </template>
        </el-table-column>
    </el-table>
    </div>

    <div v-show="!isShowList">
      <span>属性名</span>
      <el-input v-model="attr.attrName" style="width: 200px; margin-left: 15px;"> </el-input>
    

      <div style="margin: 20px 0;">
        <el-button type="primary" :icon="Plus" @click="addAttrValue">添加属性值</el-button>
        <el-button @click="isShowList=true">取消</el-button>
      </div>

      <el-table :data="attr.attrValueList">
          <el-table-column label="序号" type="index" width="80" align="center"></el-table-column>
          <el-table-column label="属性值名称">
          <template #default="{row,$index}">
            <!-- 通过判断标识isEdit来确定是显示span还是显示input -->
            <el-input ref="inputRef" v-if="row.isEdit" v-model="row.valueName" @blur="toShow(row,$index)"></el-input>
            <span style="display:inline-block;width:100% " v-else @click="toEdit(row)">{{ row.valueName }}</span>
          </template>
        </el-table-column>
          <el-table-column label="操作">
            <template #default="{$index}">
              <el-button type="danger" size="small" :icon="Delete" @click="attr.attrValueList.splice($index,1)"></el-button>
            </template>
          </el-table-column>
      </el-table>

      <div style="margin: 20px 0;">
          <el-button type="primary" @click="save" :disabled="isSaveDisabled">保存</el-button>
          <el-button @click="isShowList=true">取消</el-button>
      </div>
    </div>
  </el-card>
  </div>
</template>

<script lang="ts">
export default {
  name: 'Attr',
}
</script>

<script lang="ts" setup>
import { deleteAttrApi, getAttrListApi, saveAttrApi } from '@/api/product/attr';
import type { AttrListModel, AttrModel, AttrValueModel } from '@/api/product/model/AttrModel';
import { useCategoryStore } from '@/stores/category';
import { Delete, Edit, Plus } from '@element-plus/icons-vue';
import { ElMessage, type ElInput } from 'element-plus';
import { cloneDeep } from 'lodash';
import { storeToRefs } from 'pinia';
import { computed, nextTick, reactive,ref,watch } from 'vue';

// 用来判断是否禁用保存按钮的计算属性
const isSaveDisabled = computed(()=>{
  // 只有指定属性名及至少有一个属性值（必须有属性值名称）
  const hasName = !!attr.attrName
  // 判断属性值列表中是否至少有一个有属性值名称
  const hasAttrValue = attr.attrValueList.some(value => value.valueName)

  // 如果没有属性名或者没有属性值都是禁用的, 返回true
  return !hasName || !hasAttrValue
})



// 删除指定的属性
const remove = async (id:number)=>{
  // 请求删除接口
  await deleteAttrApi(id)
  // 成功之后：提示/重新获取列表
  ElMessage.success('删除成功！')
  getList()
}


/* 添加/更新属性 start */

// 请求保存属性
const save = async()=>{
  // 发请求前整理/处理要提交的数据：attr
  // 删除属性值对象中的isEdit
  attr.attrValueList.forEach(value=>delete value.isEdit)
  // 指定categoryId的值category3Id.value
  attr.categoryId = category3Id.value as number
  // 发送添加/更新属性的请求
  await saveAttrApi(attr)
  // 成功后，提示/回到列表页面/重新获取列表
  ElMessage.success('保存成功！')
  isShowList.value = true
  getList()
}

const addAttrValue = ()=>{
  // 创建一个新的属性值对象
  const attrValue:AttrValueModel={
    valueName:'',
    attrId:attr.id,
    isEdit:true,
  }
  // 添加到属性值列表中attr.attrValueList
  attr.attrValueList.push(attrValue)

  // 自动获取焦点：nextTickk + input.focus()
  nextTick(()=>
    inputRef.value?.focus()
  )
}


// typeof: 得到类型
// InstanceType: 得到实例的类型   ==> 指定ref中的value保存el-input组件对象
const inputRef = ref<InstanceType<typeof ElInput>>()
// 变为编辑模式
const toEdit = (row: AttrValueModel) => {
  // 将isEdit变为true
  row.isEdit = true
  
 // 通过ref得到ElInput, 并调用其focus方法获得焦点
  // 不行: 更新数据后, dom是异步更新的, 直接同步获取不到更新后dom
  // inputRef.value?.focus()
  // 解决: 等到dom更新后再去获取 => 使用nextTick
  nextTick(() => {
    inputRef.value?.focus()
  })
}


// 变为查看模式
const toShow = (row: AttrValueModel,index:number) => {
  // 如果没有名称, 失去焦点时存在一个空行  ==> 删除这个属性值对象
  if (!row.valueName) {
    attr.attrValueList.splice(index, 1)
    return
  }
  // 如果与其它重名了, 失去焦点存在同名的2行 ==>  删除这个属性值对象
  // attr.attrValueList [{}, {valueName: 'a'}, {valueName: 'a'}]
  // 方式一: 如果有2个属性值对象的valueName等于row.valueName, 就重名了
  // const isRepeat = attr.attrValueList.filter(value => value.valueName===row.valueName).length===2
  // 方式二: 如果除了自己外, 还有一个的valueName等于row.valueName, 就重名了
  const isRepeat = attr.attrValueList.some(item => item!=row && item.valueName===row.valueName)
  if (isRepeat) {
    attr.attrValueList.splice(index, 1)
    return
  }
  // 将isEdit变为false
  row.isEdit = false
}

// 是否显示列表
const isShowList = ref(true)
  const initAttr = ()=>({
    attrName:'',
    attrValueList:[],
    categoryId:0,
    categoryLevel:3
  })
// const attr = reactive<AttrModel>({
//   attrName: '',
//   attrValueList: [],
//   categoryId: 0,
//   categoryLevel: 3
// })
  
const attr = reactive<AttrModel>(initAttr())
// 显示添加页面
const showAdd=() => {
  // 重置attr
  // Object.assign(obj1, ...objs) // 将后面任意多个对象中的属性添加到obj1中
  // Object.assign(attr, {
  //   attrName: '',
  //   attrValueList: [],
  //   categoryId: 0,
  //   categoryLevel: 3
  // })
 Object.assign(attr,initAttr())
  // 显示
  isShowList.value = false
}
// 显示更新属性界面
const showUpdate = (row:AttrModel)=>{
  // 将当前指定的属性对象保存中attr中
  // Object.assign(attr,row)
   // 共享同一个attrValueList, 里面的attrValue也是同一个 => 修改时就直接修改
  // Object.assign(attr, row)   
  // 解决办法: 使用lodash对row进行深拷贝
  Object.assign(attr, cloneDeep(row)) 
  // 显示
  isShowList.value = false
}
/* 添加/更新属性 end */



/* 属性列表 start*/
const attrList = ref<AttrListModel>([])
// 取出pinia管理的三级分类id
const {category1Id,category2Id,category3Id} = storeToRefs(useCategoryStore())
// 监听category3Id
watch(category3Id,(val)=>{
  // 有值时才去请求，没有清除已有属性列表
  if(val){
    getList()
  }else{
    // 清空arrtList
    attrList.value = []
  }
})
// 封装getList函数, 请求获取属性列表
async function getList (){
      // 请求获取属性列表，并保存到attrList
  attrList.value = await getAttrListApi({
      category1Id:category1Id.value as number,
      category2Id:category2Id.value as number,
      category3Id:category3Id.value as number,
    })

}
/* 属性列表 end */
</script>

<style lang="scss" scoped>

</style>
